package com.haircut.sys.service.role.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.haircut.sys.constant.Constants;
import com.haircut.sys.dao.role.SysRoleMapper;
import com.haircut.sys.dao.role.SysRoleMenuRelMapper;
import com.haircut.sys.dao.user.SysUserMapper;
import com.haircut.sys.model.menu.SysMenu;
import com.haircut.sys.model.role.SysRole;
import com.haircut.sys.model.role.SysRoleMenuRel;
import com.haircut.sys.model.user.SysUser;
import com.haircut.sys.service.role.IRoleService;
import com.haircut.sys.utils.PageUtils;
import com.haircut.sys.utils.menu.MenuUtils;
import com.haircut.sys.utils.user.SecurityUtils;
import com.haircut.sys.vo.menu.MenuReqVo;
import com.haircut.sys.vo.menu.MenuTreeVo;
import com.haircut.sys.vo.menu.MenuVo;
import com.haircut.sys.vo.role.*;
import com.haircut.sys.vo.user.LoginUserVo;
import com.modular.constant.BaseCodeDesc;
import com.modular.constant.NumberConstant;
import com.modular.enums.DataSource;
import com.modular.enums.DataStts;
import com.modular.exception.ModularException;
import com.modular.query.BatchQuery;
import com.modular.result.PageResult;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class RoleServiceImpl implements IRoleService {

    @Autowired
    private SysRoleMapper sysRoleMapper;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private SysRoleMenuRelMapper sysRoleMenuRelMapper;
    @Autowired
    @Qualifier("modularSnowflake")
    private Snowflake snowflake;
    /**
     * 根据Id查询角色信息
     * @param roleId
     * @return
     */
    @Override
    public RoleVo findDetail(String roleId)
    {
        SysRole role = sysRoleMapper.selectById(roleId);
        RoleVo roleVo = new RoleVo();
        BeanUtils.copyProperties(role,roleVo);
        roleVo.setMenuIdList(sysRoleMenuRelMapper.findeMenuIdListByRoleId(roleId));
        return  roleVo;
    }

    /**
     * 根据角色id集合查询结束名称信息
     * @param roleIdList
     * @return
     */
    @Override
    public Map<String, RoleSimpleVo> findRoleMapByRoleIdList(List<String> roleIdList){
        if(CollUtil.isEmpty(roleIdList)){
            return Collections.emptyMap();
        }
        roleIdList = roleIdList.stream().distinct().toList();
        List<SysRole> roleList = sysRoleMapper.selectBatchIds(roleIdList);
        if(CollUtil.isEmpty(roleList)){
            return Collections.emptyMap();
        }
        return roleList.stream().collect(Collectors.toMap(SysRole::getId,p->{
            RoleSimpleVo simpleVo = new RoleSimpleVo();
            BeanUtils.copyProperties(p,simpleVo);
            return simpleVo;
        }));
    }

    /**
     * 保存角色信息
     * @param roleVo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveRole(RoleReqVo roleVo)
    {
        String userId = SecurityUtils.getUserId();
        Date currDate = DateUtil.date();
        SysRole role = new SysRole();
        BeanUtils.copyProperties(roleVo,role,"menuIdList");
        role.setId(snowflake.nextIdStr());
        role.setCreateDate(currDate);
        role.setModifyDate(currDate);
        role.setCreateUserId(userId);
        role.setModifyUserId(userId);
        role.setDataStts(DataStts.ENABLED.getCode());
        role.setDataSource(DataSource.USER.getCode());
        role.setSortNum(Opt.ofNullable(role.getSortNum()).orElse(NumberConstant.ZERO));
        sysRoleMapper.insert(role);
        saveOrUpdateMenu(roleVo.getMenuIdList(),role.getId());
    }

    private void saveOrUpdateMenu(List<String> menuIdList,String roleId){
        LambdaQueryWrapper<SysRoleMenuRel> query = Wrappers.lambdaQuery();
        query.eq(SysRoleMenuRel::getRoleId,roleId);
        sysRoleMenuRelMapper.delete(query);
        List<SysRoleMenuRel> roleRelList = new ArrayList<>(menuIdList.size());
        SysRoleMenuRel roleRel = null;
        for(String menuId:menuIdList){
            roleRel = new SysRoleMenuRel();
            roleRel.setMenuId(menuId);
            roleRel.setRoleId(roleId);
            roleRel.setId(snowflake.nextIdStr());
            roleRelList.add(roleRel);
        }
        BatchQuery<String,SysRoleMenuRel> batchQuery = new BatchQuery<>();
        batchQuery.excute((list, map) -> {
            sysRoleMenuRelMapper.batcInsert(list);
            return null;
        },roleRelList);

    }

    /**
     * 修改角色信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyRole(RoleReqVo roleVo)
    {
        SysRole role = sysRoleMapper.selectById(roleVo.getId());
        if(ObjectUtil.isNull(role)){
            throw  new ModularException(BaseCodeDesc.DEFATUL_MSG,"角色不存在，不能修改");
        }
        String userId = SecurityUtils.getUserId();
        Date currDate = DateUtil.date();
        LambdaUpdateWrapper<SysRole> modify = Wrappers.lambdaUpdate();
        modify.set(SysRole::getModifyDate,currDate).set(SysRole::getModifyUserId,userId);
        modify.set(SysRole::getRoleName,roleVo.getRoleName());
        modify.set(SysRole::getRoleDesc,roleVo.getRoleDesc());
        modify.set(SysRole::getDataScope,roleVo.getDataScope());
        modify.set(SysRole::getSortNum, Opt.ofNullable(roleVo.getSortNum()).orElse(NumberConstant.ZERO));
        modify.eq(SysRole::getId,roleVo.getId());
        sysRoleMapper.update(modify);
        saveOrUpdateMenu(roleVo.getMenuIdList(),roleVo.getId());

    }

    /**
     * 删除角色信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(String roleId)
    {
        SysRole role = sysRoleMapper.selectById(roleId);
        if(ObjectUtil.isNull(role)){
            throw  new ModularException(BaseCodeDesc.DEFATUL_MSG,"角色不存在，不能删除");
        }
        LambdaQueryWrapper<SysUser> userQuery = Wrappers.lambdaQuery();
        userQuery.eq(SysUser::getRoleId,roleId);
        Long userCount =  sysUserMapper.selectCount(userQuery);
        if(ObjectUtil.isNotNull(userCount) && userCount.intValue() > NumberConstant.ZERO){
            throw  new ModularException(BaseCodeDesc.DEFATUL_MSG,"角色下有用户，不能删除");
        }

        sysRoleMapper.deleteById(roleId);
        LambdaQueryWrapper<SysRoleMenuRel> query = Wrappers.lambdaQuery();
        query.eq(SysRoleMenuRel::getRoleId,roleId);
        sysRoleMenuRelMapper.delete(query);
    }

    /**
     * 查询角色列表
     * @param reqVo
     * @return
     */
    @Override
    public PageResult<RolePageResVo> findPage(ReolePageReqVo reqVo)
    {
        IPage<?> pageReq = Page.of(reqVo.getPageNum(),reqVo.getPageSize());
        Page<RolePageResVo> page = sysRoleMapper.findPage(pageReq,reqVo);
        if(ObjectUtil.isNull(page)  || CollUtil.isEmpty(page.getRecords())){
            return PageUtils.cover(reqVo);
        }
        return PageUtils.cover(page);
    }

    /**
     * 根据角色拆线呢登录的权限信息
     * @param roleId
     * @return
     */
    @Override
    public List<String> findLoginPermissionList(String roleId)
    {
        return sysRoleMenuRelMapper.findAuthPermissionList(roleId);
    }
    /**
     * 根据父级的菜单查询数据
     * @param reqVo
     * @return
     */
    @Override
    public List<MenuVo> findMenuByParentId(MenuReqVo reqVo)
    {
        List<SysMenu> menuList = sysRoleMenuRelMapper.findByRoleId(reqVo);
        if(CollUtil.isEmpty(menuList)){
            return Collections.emptyList();
        }
        List<MenuVo> menuVoList =  new ArrayList<>(menuList.size());
        MenuVo menuVo = null;
        for(SysMenu menu:menuList){
            menuVo = new MenuVo();
            BeanUtils.copyProperties(menu,menuVo);
            reqVo.setParentId(menuVo.getId());
            menuVo.setChildren(findMenuByParentId(reqVo));
            menuVoList.add(menuVo);
        }
        return menuVoList;
    }

    /**
     * 查询有全新的权限树
     * @return
     */
    @Override
    public List<MenuTreeVo> menuTreeByRoleId(String roleId)
    {
        LoginUserVo loginUserVo =  SecurityUtils.getLoginUser();
        MenuReqVo reqVo = new MenuReqVo();
        reqVo.setRoleId(loginUserVo.getRoleId());
        reqVo.setParentId(Constants.DEFAULT_PARENT_ID);
        List<MenuVo> menuVoList =   findMenuByParentId(reqVo);
        return MenuUtils.coverTree(menuVoList);
    }

    /**
     * 查询所有的角色信息
     * @return
     */
    @Override
    public List<RolePageResVo> findAll()
    {
        return sysRoleMapper.findAll();
    }


}
